/**
 * 20.1.9：移除重写的clone（直接使用object3D的clone就行）
 */
let THREE=require('three');
import HardLine from './hard-line';

/**
 *厚度线（连续拐角）
 * 拐角处有连续uv
 * 支持虚线，不支持箭头
 *
 @param values {object} {name,value}
 color:new THREE.Color(0,1,0),  颜色
 width:0.5,  线宽
 dashSize:0.1,  虚线长
 gapSize:0.1,  虚线空白长
 perspectiveFactor:10,  透视系数
 opacity:1,  透明度
 dashFill:true,  虚线还是实线
 sizeAttenuation:true,  是否启用近大远小
 zOffset:0,  z偏移
 zoomFactor:1,  纵向uv缩放比

 材质通用属性可获取material进行编辑
 几何体通用属性可获取geometry进行编辑
 */
export default class softLine extends HardLine{
    constructor(vertices,values={}){
        super(vertices,values);
        console.warn('this class is deprecated now, use ThickLine instead!')
    }

    //----------------------------对外属性及方法----------------------------------

    /**
     * 顶点着色器
     * @returns {string}
     */
    get vertexShader(){
        return [
            '#define MAX_NODE_RAT 1.78',
            'attribute vec3 nextPosition;' ,
            'attribute vec3 prePosition;' ,
            'attribute vec3 dirPosition;' ,
            'attribute float dashMark;',
            'attribute float offset;' ,
            'attribute float distance;' ,
            'uniform float width;',
            'uniform float perspectiveFactor;' ,
            'uniform bool sizeAttenuation;' ,
            'uniform float zOffset;',
            'uniform float tolLength;',
            'uniform float zoomFactor;',
            'varying float vDistance;' ,
            'varying float vDashMark;',
            'varying vec2 vuv;',
            'float angleOfVec(vec3 a,vec3 b){',
            '   float d=dot(a,b);',
            '   float sa=a.x*a.x+a.y*a.y+a.z*a.z;',
            '   float sb=b.x*b.x+b.y*b.y+b.z*b.z;',
            '   float theta=d/sqrt(sa*sb);',
            '   return acos(clamp(theta,-1.0,1.0));',
            '}',
            'float computeAspect(){' ,
            '   float aspect=0.5625;' ,
            '   if(projectionMatrix[3][3]==0.0){' ,
            '      float _tan=projectionMatrix[1][1];' ,
            '      float as_tan=1.0/projectionMatrix[0][0];' ,
            '      aspect=1.0/(as_tan*_tan);' ,
            '   }else{' ,
            '      float _height=1.0/projectionMatrix[1][1];' ,
            '      float _width=1.0/projectionMatrix[0][0];' ,
            '      aspect=_height/_width;' ,
            '   }' ,
            '   return aspect;' ,
            '}',
            'void main(){' ,
            '   vec4 pmvPosition=projectionMatrix*modelViewMatrix*vec4(position,1.0);' ,
            '   vec4 pmvNextPosition=projectionMatrix*modelViewMatrix*vec4(nextPosition,1.0);' ,
            '   vec4 pmvDirPosition=projectionMatrix*modelViewMatrix*vec4(dirPosition,1.0);' ,
            '   vec4 pmvPrePosition=projectionMatrix*modelViewMatrix*vec4(prePosition,1.0);' ,
            '   vec3 nxtP=pmvNextPosition.xyz/abs(pmvNextPosition.w);' ,
            '   vec3 curP=pmvPosition.xyz/abs(pmvPosition.w);' ,
            '   vec3 dirP=pmvDirPosition.xyz/abs(pmvDirPosition.w);' ,
            '   vec3 preP=pmvPrePosition.xyz/abs(pmvPrePosition.w);' ,
            '   vec3 look=vec3(0.0,0.0,1.0);' ,
            '   vec3 doubleDir=nxtP-curP;' ,
            '   vec3 CPP=curP-preP;' ,
            '   vec3 DCP=dirP-curP;' ,

            '   float aspect=computeAspect();' ,
            '   vec3 tripleDir=normalize(CPP)+normalize(DCP);' ,
            '   doubleDir.y*=aspect;',
            '   tripleDir.y*=aspect;',
            '   vec3 doubleCross=normalize(cross(look,doubleDir));' ,
            '   vec3 tripleCross=normalize(cross(look,tripleDir));' ,
            '   doubleCross.x*=aspect;' ,
            '   tripleCross.x*=aspect;' ,
            '   float DTAngle=abs(angleOfVec(-CPP,DCP));' ,
            '   vec3 dirCross=normalize(cross(-CPP,DCP));' ,
            '   float dirDot=dot(look,dirCross);' ,
            '   float sAngle=1.5707963-DTAngle*0.5;' ,
            '   float cv=cos(sAngle);' ,
            '   float dWidth=width;' ,

            '   if(projectionMatrix[3][3]!=0.){' ,
            '       if(sizeAttenuation){' ,
            '           dWidth*=projectionMatrix[1][1];' ,
            '       }' ,
            '   }' ,

            '   dWidth=dWidth/cv;' ,
            '   if(dWidth>MAX_NODE_RAT*width){' ,
            '      dWidth=MAX_NODE_RAT*width;' ,
            '   }' ,
            '   vec3 offsetVec=vec3(0.);',

            '   if(dirDot>0.0){' ,
            '      if(offset>0.0){' ,
            '         if(sizeAttenuation){' ,
            '            offsetVec=offset*doubleCross*dWidth/perspectiveFactor;' ,
            '         }else{' ,
            '            offsetVec=offset*doubleCross*dWidth/perspectiveFactor*pmvPosition.w;' ,
            '         }',
            '         gl_Position=vec4(vec3(pmvPosition.xyz)+offsetVec,pmvPosition.w);' ,
            '      }else{' ,
            '         if(sizeAttenuation){' ,
            '            offsetVec=tripleCross*dWidth/perspectiveFactor;' ,
            '         }else{' ,
            '            offsetVec=tripleCross*dWidth/perspectiveFactor*pmvPosition.w;' ,
            '         }',
            '         gl_Position=vec4(vec3(pmvPosition.xyz)-offsetVec,pmvPosition.w);' ,
            '      }' ,
            '   }else{' ,
            '      if(offset>0.0){' ,
            '         if(sizeAttenuation){' ,
            '            offsetVec=tripleCross*dWidth/perspectiveFactor;' ,
            '         }else{' ,
            '            offsetVec=tripleCross*dWidth/perspectiveFactor*pmvPosition.w;' ,
            '         }',
            '         gl_Position=vec4(vec3(pmvPosition.xyz)+offsetVec,pmvPosition.w);' ,
            '      }else{' ,
            '         if(sizeAttenuation){' ,
            '            offsetVec=doubleCross*dWidth/perspectiveFactor;' ,
            '         }else{' ,
            '            offsetVec=doubleCross*dWidth/perspectiveFactor*pmvPosition.w;' ,
            '         }',
            '         gl_Position=vec4(vec3(pmvPosition.xyz)-offsetVec,pmvPosition.w);' ,
            '      }' ,
            '   }' ,
            '   vDistance=distance;' ,
            '   vuv=vec2(distance*zoomFactor,sign(offset)*0.5);',
            '   vDashMark=dashMark;',
            '}'
        ].join('\n');
    }

    /**
     * 纵向uv缩放比
     * @param factor
     */
    set zoomFactor(factor){
        this._props.zoomFactor.value=factor;
    }
    get zoomFactor(){
        return this._props.zoomFactor.value;
    }

    /**
     * 更新几何体
     */
    updateGeometry() {
        super.updateGeometry();
        this.geometry.getAttribute('prePosition').copyArray(this._prePositions);
        this.geometry.getAttribute('dirPosition').copyArray(this._dirPositions);
        this.geometry.getAttribute('prePosition').needsUpdate = true;
        this.geometry.getAttribute('dirPosition').needsUpdate = true;
    }

    /**
     * 销毁释放
     */
    dispose() {
        super.dispose();
        this._prePositions=null;
        this._dirPositions=null;
        this._tV4=null;
        this._tV5=null;
        this._tV6=null;
    }

    //----------------------------------私有属性及方法------------------------------------

    _initProps(){
        super._initProps();
        this._props.remove('arrowMode','arrowLengthRat','arrowWidthRat');
        this._props.add({
            zoomFactor:this._values.zoomFactor||1
        });

    }
    _initPropCallback() {
        super._initPropCallback();
        this._props.onKeyChange('zoomFactor',(_new,_old)=>{
              this.material.uniforms.zoomFactor.value=_new;
        });
    }

    _initVariable(){
        super._initVariable();
        let s=this._maxSegments;
        let s3=(2*s-3)*6*3;
        this._prePositions=new Float32Array(s3);
        this._dirPositions=new Float32Array(s3);
        this._tV4=new THREE.Vector3();
        this._tV5=new THREE.Vector3();
        this._tV6=new THREE.Vector3();
    }
    _reRangeData(){
        let reRange=super._reRangeData();
        if(reRange){
            let s3=(2*this._maxSegments-3)*6*3;
            this._prePositions=new Float32Array(s3);
            this._dirPositions=new Float32Array(s3);
            this.geometry.setAttribute('prePosition', new THREE.BufferAttribute(this._prePositions, 3));
            this.geometry.setAttribute('dirPosition', new THREE.BufferAttribute(this._dirPositions, 3));
        }
        return reRange;
    }
    _rectifyPoints(ps) {
        // this.arrowWidth = 0;
        // this.arrowLength = 0;
        return ps;
    }
    _getData(){
        this._rectifyVerts=this._rectifyPoints(this._verts);
        if(this._rectifyVerts.length<2){
            console.warn('At least 2 points needed!');
            return;
        }
        this._reRangeData();
        this._pushSolidData(this._rectifyVerts);
    }
    _pushData(i3,i1,c,n,o,dm,pp,dp){
        this._offsets[i1]=o;
        this._dashMarks[i1]=dm;
        this._positions[i3]=c.x;
        this._positions[i3+1]=c.y;
        this._positions[i3+2]=c.z;
        this._nextPositions[i3]=n.x;
        this._nextPositions[i3+1]=n.y;
        this._nextPositions[i3+2]=n.z;

        this._prePositions[i3]=pp.x;
        this._prePositions[i3+1]=pp.y;
        this._prePositions[i3+2]=pp.z;
        this._dirPositions[i3]=dp.x;
        this._dirPositions[i3+1]=dp.y;
        this._dirPositions[i3+2]=dp.z;
    }
    _pushSolidData(vs){
        let n0=this._tV0;
        let n1=this._tV1;
        let pp0=this._tV2;
        let pp1=this._tV3;
        let dp0=this._tV4;
        let dp1=this._tV5;
        let nnp=this._tV6;
        for(let i=0;i<vs.length-1;i++){
            let cp=vs[i];
            let np=vs[i+1];
            if(i===0){
                n0.copy(np);
                n1.subVectors(np,cp).normalize().add(np);

                pp1.copy(cp);
                pp0.subVectors(cp,np).add(cp);
                if(vs[i+2]){
                    nnp.copy(vs[i+2]);
                }else{
                    // nnp.subVectors(np,cp).add(np);
                    nnp.copy(n1);
                }
                dp0.copy(np);
                dp1.copy(nnp);

                this._pushData(0,0,cp,n0,1,1,pp0,dp0);
                this._pushData(3,1,cp,n0,-1,1,pp0,dp0);
                this._pushData(6,2,np,n1,1,1,pp1,dp1);
                this._pushData(9,3,cp,n0,-1,1,pp0,dp0);
                this._pushData(12,4,np,n1,-1,1,pp1,dp1);
                this._pushData(15,5,np,n1,1,1,pp1,dp1);
            }else{
                let i3=18+(i-1)*36;
                let i1=6+(i-1)*12;
                n0.subVectors(cp,vs[i-1]).normalize().add(cp);
                n1.copy(np);

                pp0.copy(vs[i-1]);
                pp1.copy(vs[i-1]);
                dp0.copy(np);
                dp1.copy(np);

                this._pushData(i3,i1,cp,n0,1,1,pp0,dp0);
                this._pushData(i3+3,i1+1,cp,n0,-1,1,pp0,dp0);
                this._pushData(i3+6,i1+2,cp,n1,1,1,pp1,dp1);
                this._pushData(i3+9,i1+3,cp,n0,-1,1,pp0,dp0);
                this._pushData(i3+12,i1+4,cp,n1,-1,1,pp1,dp1);
                this._pushData(i3+15,i1+5,cp,n1,1,1,pp1,dp1);

                n0.copy(np);
                n1.subVectors(np,cp).normalize().add(np);

                if(vs[i+2]){
                    nnp.copy(vs[i+2]);
                }else{
                    // nnp.subVectors(np,cp).add(np);
                    nnp.copy(n1);
                }
                pp0.copy(vs[i-1]);
                pp1.copy(cp);
                dp0.copy(np);
                dp1.copy(nnp);

                this._pushData(i3+18,i1+6,cp,n0,1,1,pp0,dp0);
                this._pushData(i3+21,i1+7,cp,n0,-1,1,pp0,dp0);
                this._pushData(i3+24,i1+8,np,n1,1,1,pp1,dp1);
                this._pushData(i3+27,i1+9,cp,n0,-1,1,pp0,dp0);
                this._pushData(i3+30,i1+10,np,n1,-1,1,pp1,dp1);
                this._pushData(i3+33,i1+11,np,n1,1,1,pp1,dp1);
            }
        }
    }
    _initGeometry() {
        super._initGeometry();
        this.geometry.setAttribute('prePosition', new THREE.BufferAttribute(this._prePositions, 3));
        this.geometry.setAttribute('dirPosition', new THREE.BufferAttribute(this._dirPositions, 3));
    }
    _initMaterial(){
        super._initMaterial();
        this.material.uniforms.zoomFactor={value:this._props.zoomFactor.value};
        this.material.needsUpdate=true;
    }
}

